//
// Created by yfux on 2022/4/18.
//

#include <malloc.h>
#include <cstring>
#include <cmath>
#include <locale>
#include "ICanPlayer.h"
#include "Log.h"

void ICanPlayer::setDataSource(const char *path_) {
    path = static_cast<char *>(malloc(strlen(path_) + 1));
    memset(path, 0, strlen(path_) + 1);
    memcpy(path, path_, strlen(path_));
}

void *prepare_t(void *args) {
    ICanPlayer *iCanPlayer = static_cast<ICanPlayer *>(args);
    iCanPlayer->_prepare();
    return 0;
}

void ICanPlayer::prepare() {
    pthread_create(&prepareThread, NULL, prepare_t, this);
//    LOGE("prepare : [%d]", pthread_gettid_np(prepareThread));
}

void ICanPlayer::_prepare() {
    avFormatContext = avformat_alloc_context();
    int ret = avformat_open_input(&avFormatContext, path, NULL, NULL);
    if (ret != 0) {
        //failed ,print log
        LOGE("打开文件: %s失败,返回值: %d,错误信息: %s.", path, ret, av_err2str(ret));
        javaCallHelper->onError(FFMPEG_CAN_NOT_OPEN_URL, THREAD_CHILD);
        return;
    }
    ret = avformat_find_stream_info(avFormatContext, NULL);
    if (ret < 0) {
        //failed
        LOGE("查找媒体流失败,返回值: %d,错误信息: %s.", ret, av_err2str(ret));
        javaCallHelper->onError(FFMPEG_CAN_NOT_FIND_STREAMS, THREAD_CHILD);
        return;
    }

    //get duration
    duration = avFormatContext->duration / AV_TIME_BASE;

    //solve each stream of file
    for (int i = 0; i < avFormatContext->nb_streams; i++) {
        AVStream *avStream = avFormatContext->streams[i];
        AVCodecParameters *avCodecParameters = avStream->codecpar;
        AVCodec *avCodec = avcodec_find_decoder(avCodecParameters->codec_id);
        if (avCodec == NULL) {
            LOGE("查找解码器失败");
            javaCallHelper->onError(FFMPEG_FIND_DECODER_FAIL, THREAD_CHILD);
            return;
        }
        AVCodecContext *avCodecContext = avcodec_alloc_context3(avCodec);
        if (avCodecContext == NULL) {
            LOGE("获取解码上下文失败");
            javaCallHelper->onError(FFMPEG_ALLOC_CODEC_CONTEXT_FAIL, THREAD_CHILD);
            return;
        }
        ret = avcodec_parameters_to_context(avCodecContext, avCodecParameters);
        if (ret < 0) {
            LOGE("错误码: %d,错误信息: %s.", ret, av_err2str(ret));
            javaCallHelper->onError(FFMPEG_CODEC_CONTEXT_PARAMETERS_FAIL, THREAD_CHILD);
            return;
        }
        ret = avcodec_open2(avCodecContext, avCodec, NULL);
        if (ret) {
            LOGE("错误码: %d,错误信息: %s.", ret, av_err2str(ret));
            javaCallHelper->onError(FFMPEG_OPEN_DECODER_FAIL, THREAD_CHILD);
            return;
        }

        if (avCodecParameters->codec_type == AVMEDIA_TYPE_AUDIO) {
            audioPlayer = new AudioPlayer(i, javaCallHelper, avCodecContext, avStream->time_base);
        } else if (avCodecParameters->codec_type == AVMEDIA_TYPE_VIDEO) {
            double fps = av_q2d(avStream->avg_frame_rate);
            if (isnan(fps) || fabs(fps) < 1e-8) {
                fps = av_q2d(avStream->r_frame_rate);
            }
            if (isnan(fps) || fabs(fps) < 1e-8) {
                fps = av_q2d(av_guess_frame_rate(avFormatContext, avStream, NULL));
            }
            videoPlayer = new VideoPlayer(i, javaCallHelper, avCodecContext, avStream->time_base,
                                          fps);
            videoPlayer->setWindow(this->window);
            width = avCodecContext->width;
            height = avCodecContext->height;
        }
    }
    if (!videoPlayer && !audioPlayer) {
        // no video and audio
        LOGE("不存在视频与音频文件，无法播放");
        javaCallHelper->onError(FFMPEG_NO_MEDIA, THREAD_CHILD);
        return;
    }

//    LOGE("prepared OK!");

    //prepared tell java
    LOGE("width=%d,height=%d", width, height);
    javaCallHelper->onPrepare(width, height, THREAD_CHILD);

}

ICanPlayer::ICanPlayer() {
    avformat_network_init();
    videoPlayer = NULL;
    audioPlayer = NULL;
}

ICanPlayer::ICanPlayer(JavaCallHelper *javaCallHelper) : javaCallHelper(javaCallHelper) {
    avformat_network_init();
    videoPlayer = NULL;
    audioPlayer = NULL;
}

void *start_t(void *args) {
    ICanPlayer *iCanPlayer = static_cast<ICanPlayer *>(args);
    iCanPlayer->_start();
    return 0;
}

void ICanPlayer::start() {
    // read data

    // push to queue
    isPlaying = true;
    if (videoPlayer) {
        videoPlayer->audioPlayer = audioPlayer;
        videoPlayer->play();
    }
    if (audioPlayer) { audioPlayer->play(); }
//    LOGE("start ...");
    pthread_create(&startThread, NULL, start_t, this);
//    LOGE("start : [%d]", pthread_gettid_np(startThread));
}

void ICanPlayer::_start() {
    int ret;
    while (isPlaying) {
        AVPacket *avPacket = av_packet_alloc();
//        if (avPacket == NULL)LOGE("null pointer");
//        if (avFormatContext == NULL) LOGE("null pointer");
        ret = av_read_frame(avFormatContext, avPacket);
        if (ret == 0) {
            //read data success
            if (videoPlayer && avPacket->stream_index == videoPlayer->channelId) {
                // video
                videoPlayer->avPacket_queue.push(avPacket);
//                LOGE("size ======= %d", videoPlayer->avPacket_queue.size());
                if (videoPlayer->avPacket_queue.size() > 50 && isPlaying) {
                    av_usleep(1000 * 10 * videoPlayer->avPacket_queue.size() / 100);
                }
            } else if (audioPlayer && avPacket->stream_index == audioPlayer->channelId) {
                //audio
                audioPlayer->avPacket_queue.push(avPacket);
//                LOGE("size ======= %d", audioPlayer->avPacket_queue.size());
                if (audioPlayer->avPacket_queue.size() > 50 && isPlaying) {
                    av_usleep(1000 * 10 * videoPlayer->avPacket_queue.size() / 100);
                }
            } else {
                //释放其他流，我们只播放一个视频流和一个音频流
                av_packet_free(&avPacket);
            }
        } else if (ret == AVERROR_EOF) {
            //read of end but not play of end
            if (videoPlayer->avPacket_queue.empty() && videoPlayer->avFrame_queue.empty()) {
                // play of end
                break;
            }
        } else {
            //read failed
            break;
        }
    }
//    LOGE("STOP!!!");
    isPlaying = false;
    videoPlayer->stop();
    audioPlayer->stop();
}

void ICanPlayer::setWindow(ANativeWindow *window) {
    this->window = window;
    if (videoPlayer) {
        videoPlayer->setWindow(window);
    }
}

void ICanPlayer::stop() {
    isPlaying = false;
    pthread_join(prepareThread, 0);
    pthread_join(startThread, 0);
    release();
}

void ICanPlayer::release() {
    if (audioPlayer) {
        delete audioPlayer;
        audioPlayer = NULL;
    }
    if (videoPlayer) {
        delete videoPlayer;
        videoPlayer = NULL;
    }
    if (avFormatContext) {
        avformat_close_input(&avFormatContext);
        avformat_free_context(avFormatContext);
        avFormatContext = NULL;
    }
}

ICanPlayer::~ICanPlayer() {
    avformat_network_deinit();
    if (javaCallHelper) {
        delete javaCallHelper;
        javaCallHelper = NULL;
    }
    if (path) {
        delete[] path;
        path = NULL;
    }
}

